//animation example 2
//same as example 1 but uses configurator for all allegro initialisation
//this is a lot cleaner and requires less setup. plus changes can be made to how allegro starts
//only relevant changes to the code will be commented here, refer to example1 for a full description

#include "..\..\..\axl_animations.h"
#include "..\..\..\axl_config.h"
#include <time.h>
using namespace AXL_Projects;

//configuration stuff
//all the bitmaps and other allegro specifics will be removed when the framework library is available
Configuration* myConfiguration=NULL;
std::string message;

//stuff for the timers
volatile int xframe_count;
volatile int fps;
volatile int xgame_time;
//main game variables
static BITMAP* DblBuffer1;
static AnimationLibrary* GameLibrary;		//library of available animations
static Animation* MainAnimation;			//our animation item
static Animation* CollisionAnimation;		//for collision detection
static Animation* LogoAnimation;			//the logo grabbed as a standard animation object
											//useful for when we want to use the animation stuff like timers, etc.
static BITMAP* LogoAnimationSimple;			//grabbed directly without creating any new object and new animation stuff is available
static Animation* SpawnedAnimations[40];	//for showing lots of them

void DoMenu(int speed)
{
	//output the value read from a custom XML value
	textprintf_ex(DblBuffer1,font,0,0,makecol(255,255,255),-1,"%s",message.c_str());

	textprintf_ex(DblBuffer1,font,0,10,makecol(255,255,255),-1,"1 Change to stop at end");
	textprintf_ex(DblBuffer1,font,0,20,makecol(255,255,255),-1,"2 Change to repeat ping pong");
	textprintf_ex(DblBuffer1,font,0,30,makecol(255,255,255),-1,"3 Change to repeat from start");
	textprintf_ex(DblBuffer1,font,0,40,makecol(255,255,255),-1,"4 Change to ping pong once");
	textprintf_ex(DblBuffer1,font,0,50,makecol(255,255,255),-1,"5 Change to there back and there again");
	textprintf_ex(DblBuffer1,font,0,60,makecol(255,255,255),-1,"6 Pause");
	textprintf_ex(DblBuffer1,font,0,70,makecol(255,255,255),-1,"7 Resume");
	textprintf_ex(DblBuffer1,font,0,80,makecol(255,255,255),-1,"8 Set To Auto Animation");
	textprintf_ex(DblBuffer1,font,0,90,makecol(255,255,255),-1,"9 Set To Manual Animation - press SPACE for next frame when set");
	textprintf_ex(DblBuffer1,font,0,100,makecol(255,255,255),-1,"0 Reset to normal");
	textprintf_ex(DblBuffer1,font,0,120,makecol(255,255,255),-1,"B Fade-out in 5 seconds (animation stays on and it works just as normal)");
	textprintf_ex(DblBuffer1,font,0,130,makecol(255,255,255),-1,"C Fade-in in 5 seconds (assumes at full hiddne - if not will take less time)");
	textprintf_ex(DblBuffer1,font,0,140,makecol(255,255,255),-1,"+ Increase speed by 10ms");
	textprintf_ex(DblBuffer1,font,0,150,makecol(255,255,255),-1,"- Decrease speed by 10ms");
	textprintf_ex(DblBuffer1,font,0,160,makecol(255,255,255),-1,"F1 to F4 set countdown timer to random number of seconds");
	textprintf_ex(DblBuffer1,font,0,170,makecol(255,100,255),-1,"ESC to quit");
	textprintf_ex(DblBuffer1,font,0,180,makecol(255,100,255),-1,"Is End Animation Reached: %d",MainAnimation->ReadOnly_EndReached);
	textprintf_ex(DblBuffer1,font,0,190,makecol(255,100,255),-1,"Countdown reached: fade (%4d), C1(%4d), C2(%4d), C3(%4d), C4(%4d)",MainAnimation->ReadOnly_Timers[0],MainAnimation->ReadOnly_Timers[1],MainAnimation->ReadOnly_Timers[2],MainAnimation->ReadOnly_Timers[3],MainAnimation->ReadOnly_Timers[4]);
	textprintf_ex(DblBuffer1,font,0,200,makecol(255,100,255),-1,"Countdown value  : fade (%4.0f), C1(%4.0f), C2(%4.0f), C3(%4.0f), C4(%4.0f)",MainAnimation->ReadOnly_TimersCounter[0],MainAnimation->ReadOnly_TimersCounter[1],MainAnimation->ReadOnly_TimersCounter[2],MainAnimation->ReadOnly_TimersCounter[3],MainAnimation->ReadOnly_TimersCounter[4]);
	textprintf_ex(DblBuffer1,font,0,210,makecol(255,100,255),-1,"FPS: %d, Current Frame Speed Milliseconds: %d",fps,speed);
	textprintf_ex(DblBuffer1,font,200,230,makecol(255,255,255),-1,"s Change animation sprite");
	textprintf_ex(DblBuffer1,font,200,240,makecol(255,255,255),-1,"t Spawn lots of animations");
	textprintf_ex(DblBuffer1,font,501,211,makecol(255,255,255),-1,"Collision");
	textprintf_ex(DblBuffer1,font,501,468,makecol(255,255,255),-1,"Use Cursors");
}

//called every second to store the fps for display only
void xFpsHandler()
{
 //called every 1000 milliseconds
 fps=xframe_count; //set fps to display to user
 xframe_count=0;   //reset the count for the next loop
}
END_OF_FUNCTION(fps_handler);

//timer for the game loop for keeping fps called every required FPS value
void xgame_timer()
{
	xgame_time++;
}
END_OF_FUNCTION(xgame_timer);

bool Init()
{
	DblBuffer1=NULL;
	
	//initialise configuration object and read all allegro and custom values
	myConfiguration=new Configuration("config.xml");

	//start up allegro and leave us in a graphics state
	int r=myConfiguration->AllegroStart();
	
	if(r==0) return false;

	//read a custom value to show how easy it is
	message=myConfiguration->GetCustom("message","unknown message from config file");
	
	//fps timer and other timer locks
	fps=xframe_count=0;
	LOCK_VARIABLE(fps);
	LOCK_VARIABLE(xframe_count);
	LOCK_FUNCTION(xFpsHandler);
	LOCK_FUNCTION(xgame_timer);
	install_int(xFpsHandler,1000);
	install_int_ex(xgame_timer,BPS_TO_TIMER(60));

	DblBuffer1=create_system_bitmap(640,480);
	if (DblBuffer1==NULL) DblBuffer1=create_bitmap(640,480);
	if (DblBuffer1==NULL) return false;
	return true;
}


//loop for animation
int main(void)
{
	bool done=false;
	bool draw=false;
	bool CanMove=true;
	bool FirstSprite=true;
	bool ShowSpawned=false;
	int CollisionTest=0;

	int w,h,logow,logoh;
	int coll_x=503;
	int coll_y=218;
	int speed;
	int keypress;

	srand ( time(NULL) );
	xgame_time=1;
	Configuration::LogEntry("start",true,"test.log");	//log entry. use this instead of animation::logentry

	bool r=Init();

	if(!r)
	{
		Configuration::LogEntry("Initialise. Check config.log",false,"test.log");
		allegro_message("Failed to initialise. Check config.log\n%s",Configuration::GlobalErrorString.c_str());
		if(myConfiguration) delete myConfiguration;
		return 1;
	}
	
	SpawnedAnimations[0]=NULL;	//quickly show not set up yet

	Configuration::LogEntry("initialised",false,"test.log");
	GameLibrary=new AnimationLibrary();
	
	if(GameLibrary->LoadError)
	{
		Configuration::LogEntry("Failed to load XML. Check it is valid",false,"test.log");
		delete GameLibrary;
		return 1;
	}
	//GameLibrary->draw();
	GameLibrary->DebugData();

	//get animation via a string
	MainAnimation=new Animation(GameLibrary,"fuel");
	CollisionAnimation=new Animation(GameLibrary,"ufo");
	
	//get animation the via the library just to show how it is done
	AnimationLibraryFrames* af=GameLibrary->GetAnimation("logo");
	//this method below is quicker than the string version if the above is called outside of any critical loop
	LogoAnimation=new Animation(GameLibrary,af);
	//this version is just to grab it directly as this assumes no animation methods are required
	LogoAnimationSimple=GameLibrary->GetFirstGraphic("logo");
	MainAnimation->GetStandardDimensions(&w,&h);
	LogoAnimation->GetStandardDimensions(&logow,&logoh);
	speed=MainAnimation->GetCurrentSpeedMS();
	do {
		while(xgame_time!=0) 
		{
			draw=false;
			CanMove=false;	//manual mode only
			if(keypressed())
			{
				keypress=readkey()>>8;
				switch(keypress)
				{
				case KEY_1:
					MainAnimation->SetNewLoopType(LOOP_ONCE);
					break;
				case KEY_2:
					MainAnimation->SetNewLoopType(LOOP_REVERSEREPEAT);
					break;
				case KEY_3:
					MainAnimation->SetNewLoopType(LOOP_START);
					break;
				case KEY_4:
					MainAnimation->SetNewLoopType(LOOP_REVERSEONCE);
					break;
				case KEY_5:
					MainAnimation->SetNewLoopType(LOOP_REVERSEBACK);
					break;
				case KEY_6:
					MainAnimation->Pause();
					break;
				case KEY_7:
					MainAnimation->Resume();
					break;
				case KEY_8:
					MainAnimation->SetAutoMode(true);
					break;
				case KEY_9:
					MainAnimation->SetAutoMode(false);
					break;
				case KEY_0:
					MainAnimation->Reset();
					break;
				case KEY_S:
					if(FirstSprite) MainAnimation->SetNewAnimation("ufo");
					else MainAnimation->SetNewAnimation("fuel");
					FirstSprite=!FirstSprite;
					break;
				case KEY_T:
					if(!SpawnedAnimations[0])
					{
						Configuration::LogEntry("spawning",false,"test.log");
						for(int i=0;i<40;++i)
						{
							if(i%2) SpawnedAnimations[i]=new Animation(GameLibrary,"fuel");
							else SpawnedAnimations[i]=new Animation(GameLibrary,"ufo");
							SpawnedAnimations[i]->SetNewSpeedMS(rand()%150+50);
						}
					}
					ShowSpawned=true;
					break;
				case KEY_B:
					MainAnimation->FadeOut(5000,true,makecol(0,0,0));
					break;
				case KEY_C:
					MainAnimation->FadeIn(5000,true,makecol(0,0,0));
					break;
				case KEY_SPACE:
					CanMove=true;
					break;
				case KEY_MINUS:
					speed-=10;
					MainAnimation->SetNewSpeedMS(speed);
					break;
				case KEY_EQUALS:
					speed+=10;
					MainAnimation->SetNewSpeedMS(speed);
					break;
				case KEY_F1:
					MainAnimation->SetCustomCountDown(1,5000);
					break;
				case KEY_F2:
					MainAnimation->SetCustomCountDown(2,(rand()%5+5)*1000);
					break;
				case KEY_F3:
					MainAnimation->SetCustomCountDown(3,(rand()%5+5)*1000);
					break;
				case KEY_F4:
					MainAnimation->SetCustomCountDown(4,(rand()%5+5)*1000);
					break;
				//movement of collision
				case KEY_UP:
					if(coll_y>235) coll_y--;
					break;
				case KEY_DOWN:
					if(coll_y<460) coll_y++;
					break;
				case KEY_LEFT:
					if(coll_x>500) coll_x--;
					break;
				case KEY_RIGHT:
					if(coll_x<600) coll_x++;
					break;
				case KEY_ESC:
					done=true;
					break;
				}
				clear_keybuf();
			}

			//collision test
			//CollisionTest=check_bb_collision(CollisionAnimation->ReadOnly_CurrentPPCOLMask,MainAnimation->ReadOnly_CurrentPPCOLMask,coll_x,coll_y,570,270);
			CollisionTest=CollisionAnimation->CheckCollision(coll_x,coll_y, MainAnimation->ReadOnly_CurrentPPCOLMask, 570,270);

			//main display sprite
			if(done==false) 
			{
				if(MainAnimation->GetAutoMode()) MainAnimation->NextMove();
				else
				{	
					//if manual mode then do full move this frame if space pressed
					//otherwise just update the timers for the fade/countdown as we still
					//need these to work
					if(CanMove) MainAnimation->NextMove();
					else MainAnimation->ManualTimerUpdate();
				}
				draw=true;
			}

			xgame_time--;
		}
		//should exit loop every FRAMERATE/second second if on time
		//update display if frame has been drawn
		//if not then system is too fast so don't do anything
		if(draw) 
		{
			draw_sprite(DblBuffer1,MainAnimation->ReadOnly_CurrentItem,570,270);
			//function call order is z order
			clear_to_color(DblBuffer1,makecol(0,0,0));
			rect(DblBuffer1,500,210,639,479,makecol(255,0,0));
			DoMenu(MainAnimation->GetCurrentSpeedMS());
			blit(LogoAnimation->ReadOnly_CurrentItem,DblBuffer1,0,0,400,0,logow,logoh);
			blit(LogoAnimationSimple,DblBuffer1,0,0,400,70,logow,logoh);
			stretch_sprite(DblBuffer1, MainAnimation->ReadOnly_CurrentItem, 100,240,w*2,h*2);

			//our stuff for collision
			draw_sprite(DblBuffer1,MainAnimation->ReadOnly_CurrentItem,570,270);
			draw_sprite(DblBuffer1,CollisionAnimation->ReadOnly_CurrentItem,coll_x,coll_y);
			if(CollisionTest==1)
			{
				textprintf_ex(DblBuffer1,font,501,221,makecol(255,255,255),-1,"Bounding Only");
				rect(DblBuffer1,coll_x,coll_y,coll_x+CollisionAnimation->ReadOnly_CurrentItem->w,coll_y+CollisionAnimation->ReadOnly_CurrentItem->h,makecol(0,255,0));
				rect(DblBuffer1,570,270,570+MainAnimation->ReadOnly_CurrentItem->w,270+MainAnimation->ReadOnly_CurrentItem->h,makecol(0,0,255));
			}
			else if(CollisionTest==2)
			{
				textprintf_ex(DblBuffer1,font,501,221,makecol(255,255,255),-1,"Pixel Perfect!");
			}

			//spawned
			if(ShowSpawned)
			{
				for(int j=0;j<4;++j)
				{
					for(int k=0;k<10;++k)
					{
						SpawnedAnimations[j*10+k]->NextMove();
						draw_sprite(DblBuffer1,SpawnedAnimations[j*10+k]->ReadOnly_CurrentItem,k*50,300+j*50);
					}
				}
			}

			acquire_screen();
				blit(DblBuffer1, screen, 0, 0, 0, 0,640,480);
			release_screen();
			xframe_count++; //update every drawn screen - should match fps which is required FPS or less, cannot be higher
			draw=false;
		}

	} while(done==false);

	for(int l=0;l<40;++l)
		delete SpawnedAnimations[l];

	delete MainAnimation;
	delete CollisionAnimation;
	delete GameLibrary;

	if(DblBuffer1!=NULL) {destroy_bitmap(DblBuffer1);}
	remove_int(xFpsHandler);
	remove_int(xgame_timer);
	//delete configuration object
	if(myConfiguration) delete myConfiguration;

	//allegro_exit();

	return 0;
}
END_OF_MAIN()

//just in case allegro_core is included for logging, need this function
void GameLoop() {}

